<?php

/**
 * 
 * \file luminous_common_grammars.php
 * \brief Grammar definitions (and examples) for common languages
 * 
 * \example luminous_common_grammars.php 
 * Built in grammar definitions, browse these to get a feel for how to write
 *      your own.
 * 
 * \todo clean up regex rules with proper char classes.
 * \todo arrange the regex rules according to \ref grammar_optimisation
 * 
 */

 
require_once('luminous_grammar.class.php');


function luminous_generic_comment($delim1 = "//", $delim2 = "\n",
$callback='luminous_type_callback_comment')
{
  return new LuminousDelimiterRule(0, 'COMMENT', 0, $delim1, $delim2, 
    $callback);
}

function luminous_generic_doc_comment($delim1 = "///", $delim2 = "\n")
{
  return new LuminousDelimiterRule(0, 'DOCCOMMENT', 0, $delim1, $delim2,
  'luminous_type_callback_doccomment');
}

function luminous_generic_string($delim1 = '"', $delim2 = '"',
  $callback = 'luminous_type_callback_generic_string')
{
  return new LuminousDelimiterRule(0, 'STRING', 0, $delim1, $delim2, $callback);
}

function luminous_generic_sql_string($delimiter = "'")
{
  $regex = "/
  $delimiter{2}|
  $delimiter
  .*?
  (?<!$delimiter)
  $delimiter
  (?!$delimiter)
  /sx";
  
  return new LuminousDelimiterRule(0, 'STRING', 
    LUMINOUS_COMPLETE|LUMINOUS_REGEX, $regex, null, 
    'luminous_type_callback_sql_single_quotes');
}

function luminous_generic_regex($modifiers, 
$callback = 'luminous_type_callback_generic_regex',
  $preceding_chars = "[\(\[,=:;\?!\|\&~]")
{
  $regex = 
  "/
  (?<=($preceding_chars))
  
  [\s]* 
  \/(?![\/\*])
  (?:.*?[^\\\])*?
  (?:\\\\\\\\)*\/
  [$modifiers]*/sx";
  
  return new LuminousDelimiterRule(0, 'REGEX', LUMINOUS_REGEX|LUMINOUS_COMPLETE,
  $regex, null, $callback);
}

function luminous_generic_shebang($identifier='#!', $end="\n")
{
  return new LuminousDelimiterRule(0, 'SHEBANG', 
    LUMINOUS_REGEX|LUMINOUS_COMPLETE, "/^[\s]*$identifier.*?$end/");
}

function luminous_generic_constant()
{
  return new LuminousSimpleRule(3, 'CONSTANT', LUMINOUS_REGEX,
    '/(?<![[:alnum:]_&<])\b[A-Z_][A-Z0-9_]{2,}(?![[:alnum:]_])/');
}

function luminous_generic_generics()
{
}


/**
 * \return a generic regex literal regex rule
 */ 
function luminous_generic_regex_literal($modifiers, 
  $preceding_chars = "[
                        \(\[,=:;\?!\|\&~
                      ]")
{
  return "/
  (?<=($preceding_chars))
  [\s]* 
  \/(?![\/\*])
  (?:.*?[^\\\])*?
  (?:\\\\\\\\)*\/
  [$modifiers]*/x";
}

/**
 * \return a generic string literal regex, where it uses doubling of
 * delimiters to escape.
 */ 
function luminous_generic_str_literal_sql($delimiter='\'')
{
  return 
  "/
  (?:$delimiter$delimiter)
  |
  (?:(?:$delimiter.*?(?<!$delimiter)$delimiter)(?!$delimiter))
  /sx";
}

/// \cond 




// no point generating class docs for all of these.


/* I don't actually know ActionScript so there's definitely room for improvement
 * in this one
 */
class LuminousGrammarActionscript extends LuminousGrammar
{
  public $keywords = array('as',
  'break',
  'case|catch|class|const|continue',  
  'default|delete|do',
  'else|extends',
  'false|finally|for|function',
  'if|impements|import|in|instanceof|interface|internal|is',
  'native|new|null',
  'package|private|protected|public',
  'return',
  'super|switch',
  'this|throw|to|true|try|typeof',
  'use',
  'void',
  'while|with',  
  );
  
  public $functions = array('add', 'chr', 'clearInterval', 'escape', 'eval', 
    'evaluate', 'fscommand', 'getProperty', 'getTimer', 'getVersion', 
    'globalStyleFormat', 'gotoAndPlay', 'gotoAndStop', 'ifFrameLoaded', 
    'instanceOf', 'isFinite', 'isNaN', 'loadMovie(?:Num)?', 'loadVariables', 
    'mb(?:chr|length|ord|substring)', 'next(?:Frame|Scene)', 'onClipEvent', 
    'ord', 'parseFloat', 'parseInt', 'play', 'prev(?:Frame|Scene)', 
    'print(?:AsBitmap(?:Num)?)?', 'printNum', 'random', 'scroll', 'setInterval',
    'setProperty', 'stop(?:Drag)?', 'substring', 'super', 'targetPath', 
    'tellTarget', 'toString', 'toggleHighQuality', 'trace', 'unescape');
  
  public $types = array('Accessibility', 'Array', 'Arguments', 'Boolean', 
    'Button', 'ByteArray', 'Camera', 'Color', 'Date', 'Event', 'FScrollPane', 
    'FStyleFormat', 
    'Function', 'int', 'Key', 'LoadVars', 'LocalConnection', 'Math',
    'Microphone', 'Mouse', 'Movieclip', 'Number', 'Object', 'Selection', 
    'Sound', 'Sprite', 'String', 'System', 'Text(?:Field|Format)', 
    'Timer(?:Event)?', 'uint', 'var',  'void', 'XML');
  
  public $oo_separators = array('\.');
  function __construct()
  {
    $this->delimited_types = array(
      luminous_generic_doc_comment('/**', '*/'),
      luminous_generic_comment('//'),
      luminous_generic_comment('/*', '*/'),
      luminous_generic_string('"', '"'),
      luminous_generic_string("'", "'"),
      luminous_generic_regex('gimsx'),
      new LuminousDelimiterRule(0, 'PREPROCESSOR',
        LUMINOUS_REGEX|LUMINOUS_COMPLETE,
        '/#(include\s|initclip|endinitclip).*$/m')
    );
    
    $this->SetInfoLanguage("as");
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoVersion('0.3.1');          
    $this->SetSimpleTypeRules();
    $this->simple_types[] = luminous_generic_constant();
  }
}


class LuminousGrammarActionscriptEmbedded extends LuminousGrammarActionscript
{
  public function __construct()
  {
    parent::__construct();
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoVersion('0.3.1');
    
    $this->simple_types = array_merge( 
      array(
        new LuminousSimpleRule(0, 'COMMENT', LUMINOUS_REGEX,
        '/(?:&lt;!\[CDATA\[)|(?:\]\]&gt;)/')
        ),
        $this->simple_types
        );
    
    $this->ignore_outside = array(
      new LuminousBoundaryRule(LUMINOUS_REGEX|LUMINOUS_EXCLUDE, 
      '/&lt;[\s]*mx:Script[\s]*&gt;/i',
      '/&lt;[\s]*\/[\s]*mx:Script[\s]*&gt;/i')
      );
      
     $this->child_grammar = new LuminousGrammarHTML();
  }  
}


class LuminousGrammarBNF extends LuminousGrammar
{
  public function __construct()
  {
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
                         'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('bnf');
    $this->SetInfoVersion('0.3.1');
    $this->operators = array();
  }
  
  private function SetCommonRules()
  {
    $this->delimited_types = 
      array_merge($this->delimited_types,
        array( luminous_generic_string("'", "'"),
               luminous_generic_string("\"", "\"")
        )
      );
      
  }
  
  private function SetStrictRuleset()
  {
    $this->delimited_types = array_merge($this->delimited_types,
    array(
      new LuminousDelimiterRule(0, 'COMMENT', 0, '&lt;!', '&gt;'),
      new LuminousDelimiterRule(0, 'KEYWORD', 0, '&lt;', '&gt;')
      )
    );
    $this->operators = array('::=', '\|');
  }
  
  private function SetExtendedRuleset()
  {
    /** TODO When luminous supports proper state transitions, put the other
     * markers in here. Putting them in now will not allow nesting.
     */ 
    $this->delimited_types = array_merge($this->delimited_types,
      array(
        new LuminousDelimiterRule(0, 'COMMENT', 0, '(*', '*)')
        
        
      )
    );
    
    $this->operators = array(',', ';', '\|', '=', '\*', '(?<!\s)\?');
    $this->simple_types[] = new LuminousSimpleRule(0, 'KEYWORD', 
      LUMINOUS_REGEX, '/(^[\s]*)(.*?)([\s]*=)/m', null, 2);
    
  }
  
  
  public function SetRuleset(&$str)
  {
    $this->SetCommonRules();
    
    $s = explode("\n", $str);
    $set = false;
    foreach($s as $line)
    {
      if (preg_match("/^[\s]*&lt;[a-z0-9\-_]+&gt;[\s]*\:\:\=/i", $line))
      {
        $this->SetStrictRuleset();
        $set = true;
      }
      elseif(preg_match("/^[\s]*[a-z_\-0-9 \t]+=/i", $line))
      {
        $this->SetExtendedRuleset();
        $set = true;
      }
      
      if ($set)
        break;
    }
    
//     $this->SetStrictRuleset();
    if ($set)
      $this->SetSimpleTypeRules();
    
  }
}

class LuminousGrammarChangelog extends LuminousGrammar
{
  public function __construct()
  {
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
          'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('changelog');
    $this->SetInfoVersion('0.3.1');
    
    
    $this->delimited_types = array(
      new LuminousDelimiterRule(3, 'VALUE', LUMINOUS_REGEX,
      '/^[ \t]+[*\-\+][ \t]/m', "/$|(?=\n[ \t]*\n)/"
      )
    );
      
    
    $this->simple_types = array(
      // Changelog heading
      new LuminousSimpleRule(0, 'KEYWORD', LUMINOUS_REGEX,
        "/^[a-zA-Z0-9_].*$/m"),
      // --
      new LuminousSimpleRule(0, 'COMMENT', LUMINOUS_REGEX,
        "/^[\s]*\-\-(?!\-).*$/m"),
      // subheading, if present
      new LuminousSimpleRule(1, 'TYPE', LUMINOUS_REGEX,
        '/^[\s]+.*:[ \t]*$/m')
//       new LuminousSimpleRule(2, 'VALUE', LUMINOUS_REGEX,
//         "/(^|\n)[ \t]+(?:\*|(?:-(?!-)))[ \t].*?($|(?=(\n\n)))/s")
      
    );
  }
  
}


class LuminousGrammarCpp extends LuminousGrammar
{    
  public $keywords = array('asm|auto', 'break', 
    'case|catch|class|continue|const(?:_cast)?', 
    'default|delete|do|dynamic_cast', 'else|explicit|extern', 'for|friend', 
    'goto', 'if|inline', 'mutable', 'namespace|new', 'operator', 
    'private|protected|public', 'register|reinterpret_cast|return', 
    'static(?:_cast)?|switch|sizeof|signed', 
    'template|this|throw|try|typedef|typeid|typename', 
    'union|using|unsigned', 'virtual|volatile', 'while');
  
  public $types =  array('FALSE','FILE',
    'NULL', 'TRUE', 'bool', 'char|clock_t', 'double|div_t', 
    'enum', 'false|float|fpos_t', 'int(?:(?:8|16|32|64)_t)?',     
    'long|ldiv_t', 'short|struct', 
    'ptrdiff_t', 'true|time_t', 
    'union', 'uint(?:8|16|32|64)_t',
    'void|va_list', 'wchar_t', 'size_t',
    // C++ std stuff
    'pair', 'vector', 'list', 'deque', 'queue', 'priority_queue',
    'stack', 'set', 'multiset', 'map', 'multimap', 
    'hash_(?:set|multiset|map|multimap)', 'bitset', 'valarray', 'iterator'
    );
    
  public $oo_separators = array('\.', '-&gt;', '::');


  public $functions = array(
  
  //ctype.h
  'is(?:alnum|alpha|blank|cntrl|digit|graph|lower|print|punct|space|upper|xdigit)',
  'to(?:upper|lower)',
  
  //stdlib.h,  
  'ato[fil]', 'strto(?:[dl]|ull?|ll)', 'rand(?:om)?', 'srand(?:om)?', 'malloc',
  'calloc', 'realloc', 'free', 'abort', 'atexit', 'exit',  'getenv', 'system',
  'bsearch', 'max', 'min', 'qsort', 'abs', 'fabs', 'labs', 'div', 'ldiv',
  'mblen', 'mbtowc', 'wctomb', 'mbstowcs', 'wcstombs', 'itoa',
  
  // stdio.h
  'fclose',   'fopen',  'freopen',  'remove',  'rename',  'rewind',  'tmpfile',
  'clearerr',  'feof',  'ferror',  'fflush',  'fgetpos',  'fgetc',  'fgets',
  'fputc',  'fputs',  'ftell',  'fseek',  'fsetpos',  'fread',  'fwrite',
  'getc',  'getchar',  'gets',  'printf',  'vprintf',  'fprintf',  'vfprintf',
  'sprintf',  'snprintf',  'vsprintf',  'vsnprintf',  'perror',  'putc',
  'putchar',  'fputchar',  'scanf',  'vscanf',  'fscanf',  'vfscanf',
  'sscanf',  'vsscanf',  'setbuf',  'setvbuf',  'tmpnam',  'ungetc',  'puts',
  
  
  //string.h
  'str(?:cat|chr|cmp|coll|cpy|cspn|dup|fry|len|ncat|ncmp|ncpy|pbrk|rchr|sep|spn|str|tok|xfrm)'
  );
  
  public function __construct()
  {
    $this->SetInfoAuthor( 
      array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
        'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('cpp');
    $this->SetInfoVersion('0.3.1');
    
    
    $this->delimited_types = array(
      luminous_generic_doc_comment('/**', '*/'),
      luminous_generic_doc_comment('/*!', '*/'),
      luminous_generic_doc_comment('//!', "\n"),
      luminous_generic_doc_comment('///', "\n"),
      
      luminous_generic_comment('/*', '*/'),
      luminous_generic_comment('//', "\n"),
      luminous_generic_comment('#if 0', "#endif"),
      
      luminous_generic_string('"', '"'),
      
      new LuminousDelimiterRule(0, 'CHARACTER', 0, '\'', '\'',
        'luminous_type_callback_cstring'),
      new LuminousDelimiterRule(0, 'PREPROCESSOR', 0, '#', "\n")
    ); 
    
    $this->SetSimpleTypeRules();
    $this->simple_types[] = luminous_generic_constant();
  }
}





// TODO this
class LuminousGrammarGeneric extends LuminousGrammar
{
  
  
}


class LuminousGrammarLatex extends LuminousGrammar
{
  
  public $type_regex = "/\\\(%TYPE)/";
  public $types = array('alpha', 'theta', 'tau', 
  'beta', 'vartheta', 'pi', 'upsilon', 
  'gamma', 'gamma', 'varpi', 'phi', 
  'delta', 'kappa', 'rho', 'varphi', 
  'epsilon', 'lambda', 'varrho', 'chi', 
  'varepsilon', 'mu', 'sigma', 'psi',
  'zeta', 'nu', 'varsigma', 'omega', 
  'eta', 'xi', 
  'Gamma', 'Lambda', 'Sigma', 'Psi',
  'Delta', 'Xi', 'Upsilon', 'Omega', 
  'Theta', 'Pi', 'Phi');
  

  
  public $operators = array();
  
  public $numeric_regex = null;
  
  public function __construct()
  {
    $this->SetInfoLanguage('latex');
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoVersion('0.3.1');
    
    $this->delimited_types = array(
      new LuminousDelimiterRule(0, 'COMMENT', LUMINOUS_REGEX|LUMINOUS_COMPLETE, 
        '/(?<!\\\)%.*?$/m'),
        
      // this definitely shouldn't be variable, it's the range of a 
      // square bracket, but not nested ones
      new LuminousDelimiterRule(3, 'VARIABLE', LUMINOUS_REGEX|LUMINOUS_COMPLETE,
        '/(?<=[^\\\]\[)(?:[^\[\\\]+?)(?=(\]))/', null, null),
      
      // Curley brace
      new LuminousDelimiterRule(3, 'VALUE', LUMINOUS_REGEX|LUMINOUS_COMPLETE,
        '/(?<=[^\\\]\{)(?:[^\{\\\]+?)(?=(\}))/', null, null)
     );
     


    $this->SetSimpleTypeRules();
    
    $keyword_regex = "/\\\(%KEYWORD)/";
    
    // I'm trying to keep this more oriented towards common layout and 
    // formatting commands, not all the maths stuff, will be caught by the 
    // general rule.
    // But I haven't used LaTeX much, and when I did it was always for maths
    // (the irony).
    $keywords = array('@', 'begin', 'DisableLigatures', 'end', 'emph', 
      'fbox', 'footnotesize', 'frenchspacing', '[hH]uge', 'hyphonation', 
      '[lL]arge', 'LARGE', 'ldots', 'mathrm', 'mbox', 'newcommand', 'normalem', 
      'normalsize', 'oldstylenums', 'scriptsize', 'small', 'sout', 'tiny', 
      'text(normal|rm|sf|tt|up|it|sl|sc|bf|md|(super|sub)script|color)', 
      'ulem', 'underline', 'usepackage', 'uwave');
  
    $this->simple_types[] = new LuminousSimpleRuleList(2, 'LATEX_FUNCTION',
      LUMINOUS_REGEX, $keywords, $keyword_regex, '%KEYWORD');
    

    
    
    // kind of a generic thing to catch everything else.
    $this->simple_types[] = 
      new LuminousSimpleRule(3, 'FUNCTION', LUMINOUS_REGEX, 
        '/
          (?:\\\)
          (?:
            (?:[[:alnum:]]+)
            | [\-\\\\{\}%]
            
            )
            
        /x');
        
    $this->simple_types[] = new LuminousSimpleRuleList(4, 'LATEX_OPERATOR', 
      LUMINOUS_REGEX, array('\[', '\]', '\{', '\}'), '/(%OP)+/', '%OP');
  }
  
}



/// \todo this could do with some work, but I don't know Pascal.
class LuminousGrammarPascal extends LuminousGrammar

{
  public $case_insensitive = true;
  
  public $operators = array('(?<![a-zA-Z0-9_])and(?![a-zA-Z0-9_])', 
  '(?<![a-zA-Z0-9_])div(?![a-zA-Z0-9_])', 
    '(?<![a-zA-Z0-9_])in(?![a-zA-Z0-9_])',    
    
    '(?<![a-zA-Z0-9_])sh[lr](?![a-zA-Z0-9_])',        
    '(?<![a-zA-Z0-9_])not(?![a-zA-Z0-9_])',  
    '(?<![a-zA-Z0-9_])or(?![a-zA-Z0-9_])',
    '(?<![a-zA-Z0-9_])mod(?![a-zA-Z0-9_])',
    
    '(?<![a-zA-Z0-9_])xor(?![a-zA-Z0-9_])',
    
    '\+', '\*', '-', '\/', '=', '&[gl]t;', '=','!', '%', '&amp;', '\|','~',
    '\^', '\[', '\]');
    
  public $keywords = array(
    'absolute|abstract|all|and_then|array|as|asm',
    'begin|bindable',
    'case|class|const|constructor',
    'destructor|dispose|do|downto',
    'else|end|except|exit|export|exports',
    'false|file|finalization|finally|for|function',
    'goto',
    'if|implementation|import|inherited|initialization|inline|interface|is',
    'label|library',
    'module',
    'new|nil',
    'object|of|on|only|operator|or_else|otherwise',
    'packed|pow|procedure|program|property|protected',
    'qualified',
    'raise|record|repeat|restricted',
    'set',
    'then|threadvar|to|true|try|type',
    'unit|until|uses',
    'value|var|view|virtual',
    'while|with',
    'xor');   
  
  
  public $types = array('String', 'Integer', 'Real', 'Boolean', 'Character',
    'Byte(?:Int)?', 'Short(?:Int|Word|Real)', 'Word', 'Med(?:Int|Word)', 
    'Long(?:est)?(?:Int|Word|Real)', 'Comp', 'Smallint', 'SizeType',
    'Ptr(?:DiffType|Int|Word)',
    'Int64', 'Cardinal', 'QWord', 'ByteBool', 'WordBool', 'LongBool', 'Char');
    
  // http://www2.toki.or.id/fpcdoc/ref/refse64.html#x151-15700013.3
  public $functions = array('Abs', 'Addr', 'Append', 'Arctan', 'Assert',
    'Assign(?:ed)?', 'BinStr', 'Blockread', 'Blockwrite', 'Break', 'Chdir',
    'Chr', 'Close', 'Compare(Byte|Char|D?Word)', 'Concat', 'Copy', 'Cos',
    'CSeg', 'Dec', 'Delete', 'Dispose', 'DSeg', 'Eo(?:f|ln)', 'Erase',
    'Exclude', 'Exit', 'Exp', 'File(?:pos|size)', 'Fill(?:Byte|char|D?word)',
    'Flush', 'Frac', 'Freemem', 'Get(?:dir|mem|MemoryManager)', 'Halt',
    'HexStr', 'Hi', 'High', 'Inc(?:lude)?','Index(Byte|Char|D?Word)', 'Insert',
    'IsMemoryManagerSet', 'Int', 'IOresult', 'Length', 'Ln', 'Lo', 'LongJmp',
    'Low', 'Lowercase', 'Mark', 'Maxavail', 'Memavail', 'Mkdir', 'Move',
    'MoveChar0', 'New', 'Odd', 'OctStr', 'Ofs', 'Ord', 'Paramcount', 'Paramstr',
    'Pi', 'Pos', 'Power', 'Pred', 'Ptr', 'Random(?:ize)?', 'Read(?:ln)?',
    'Real2Double', 'Release', 'Rename', 'Reset', 'Rewrite', 'Rmdir', 'Round',
    'Runerror', 'Seek(?:Eof|Eoln)?', 'Seg', 'SetMemoryManager', 'SetJmp',
    'SetLength', 'SetString', 'SetTextBuf', 'Sin', 'SizeOf', 'Sptr', 'Sqrt?',  
    'SSeg', 'Str', 'StringOfChar', 'Succ', 'Swap', 'Trunc', 'Truncate',
    'Upcase', 'Val', 'Write(?:Ln)?');
    
    
  
  public function __construct()
  {
    $this->SetInfoLanguage('pascal');
    
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoVersion('0.3.1');          
    
    $this->delimited_types = array(
      luminous_generic_comment('{', '}'),
      luminous_generic_comment('(*', '*)'),
      luminous_generic_comment('//', "\n"),
      
      luminous_generic_sql_string("'"),
      luminous_generic_sql_string('"')
    );
    
    $this->SetSimpleTypeRules();
    
  }
  
  
  
}


class LuminousGrammarPython extends LuminousGrammar
{
  public $operators = array('(?<![a-zA-Z0-9_])and(?![a-zA-Z0-9_])', 
    '(?<![a-zA-Z0-9_])not(?![a-zA-Z0-9_])', 
    '(?<![a-zA-Z0-9_])i[ns](?![a-zA-Z0-9_])',    
    '(?<![a-zA-Z0-9_])or(?![a-zA-Z0-9_])',
    '\+', '\*', '-', '\/', '=', '&[gl]t;', '=','!', '%', '&amp;', '\|','~',
    '\^', '\[', '\]');
    
  public $keywords = array('del', 'for', 'raise', 'assert', 'elif', 'from', 
    'lambda', 'return', 'break', 'else', 'global', 'try', 'class', 'except', 
    'if', 'while','continue', 'exec', 'import', 'pass', 'yield', 'def', 
    'finally', 'print', 'as');
  
  // okay so these aren't really types but it makes it more colourful.
  public $types = array('False', 'True', 'None',
    'self',
    'int', 'float', 'long', 'complex',
    'str', 'unicode', 'list', 'tuple', 'buffer',
    'set', 'frozenset', 'dict',
    'memoryview',
    'Ellipsis',
  );
  
  public $functions = array('all', 'abs', 'any', 'basestring','bin',
    'callable', 'classmethod', 'cmp', 'compile',  'dir',
    'divmod', 'enumerate', 'eval', 'execfile', 'file', 'filter',
    'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash',
    'help', 'hex', 'id', 'input', 'isinstance', 'issubclass', 'iter',
    'len', 'locals', 'map', 'max', 'min', 'memoryview', 'next', 'object',
    'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'raw_input',
    'reduce', 'reload', 'repr', 'reversed', 'round', 'setattr', 'slice',
    'sorted', 'staticmethod', 'sum', 'super', 'type', 'unichr', 'unicode',
    'vars', 'xrange', 'zip', '__import__'
    );
  public $oo_separators = array('\.');
    
  public $numeric_regex = '
    /(?<![a-zA-Z_0-9<])  
    (?:
      #hex 
      (?:0[xX][0-9A-Fa-f]+)
    |
      (?:0[bB][0-1]+)
    |
      (?:0[oO0][0-8]+)      
    | 
      # regular number
      (?:
        [0-9]+
        (?:
          # fraction
          \.(?:[0-9]+(?:[eE]?[0-9]+)?)
        )?
      )
      |
      (?:
        # or only after the point
        \.(?:[0-9]+(?:[eE]?[0-9]+)?)
      )
    )
    [jJlL]?
    /x';
    
  public function __construct()
  {
    
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
          'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('py');
    $this->SetInfoVersion('0.3.1');    
    
    $this->delimited_types = array(
      luminous_generic_shebang(),
      luminous_generic_comment("#", "\n"),
      luminous_generic_doc_comment("'''", "'''"),
      luminous_generic_doc_comment('"""', '"""'),
      
      new LuminousDelimiterRule(0, 'STRING', LUMINOUS_REGEX, 
      '/[ruRU]{0,2}\'/', '/\'/', 'luminous_type_callback_pystring'),
      
      new LuminousDelimiterRule(0, 'STRING', LUMINOUS_REGEX, 
      '/[ruRU]{0,2}"/', '/"/', 'luminous_type_callback_pystring')    
      );
      

    
    $this->SetSimpleTypeRules();
    $this->simple_types[] = luminous_generic_constant();
    
  }
}

class LuminousGrammarRuby extends LuminousGrammar
{
  public $operators =  array('(?<![a-zA-Z0-9])and(?![a-zA-Z0-9])', 
    '(?<![a-zA-Z0-9])not(?![a-zA-Z0-9])', '(?<![a-zA-Z0-9])in(?![a-zA-Z0-9])', 
    '(?<![a-zA-Z0-9])or(?![a-zA-Z0-9])', '\+', '\*', '-', '\/', '=',  '&gt;', 
    '&lt;', '=','!', '%', '&amp;', '\|', '~', '\^', '\[', '\]');
    
  public $keywords =  array("alias", "BEGIN", "(?<!=)begin", "break", "case",
    "class", "def","defined", "do", "else", "elsif", "END", "(?<!=)end", 
    "ensure", "false", "for", "if", "module", "next", "nil", "redo", "rescue", 
    "retry", "return", "self", "super", "then", "true", "undef", "unless",
    "until", "when", "while", "yield");
    
  public $types = array('false', 'nil', 'self', 'true', '__FILE__', '__LINE__',
    'TRUE', 'FALSE', 'NIL', 'STDIN', 'STDOUT', 'STDERR', 'ENV', 'ARGF', 'ARGV', 
    'DATA', 'RUBY_(?:VERSION|RELEASE_DATE|PLATFORM)');
      
  public $oo_separators = array('\.');
  public function __construct()
  {
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('rb');
    $this->SetInfoVersion('0.3.1');        
        
    // Ruby is complicated, apparently.
    // http://www.zenspider.com/Languages/Ruby/QuickRef.html#18
    
    $this->delimited_types = array(
      new LuminousDelimiterRule(0, "DOCCOMMENT", 
        LUMINOUS_REGEX|LUMINOUS_COMPLETE, "/^=begin(?:.*?)^=end/ms"),
        
      luminous_generic_comment("#", "\n"),

      new LuminousDelimiterRule(0, "STRING", LUMINOUS_REGEX, 
        '/(?<!\$)"/', '/"/', 'luminous_type_callback_ruby_string'),
      
      new LuminousDelimiterRule(0, "STRING", LUMINOUS_REGEX, 
        '/(?<!\$)\'/', "/'/"),
        
        
      /* XXX:  
       * this is terrible, but if we leave the delimiter as 'not alnum',
       *  it starts to pick up %= and stuff which is used as a delimiter in 
       * web-ruby like <?php in php. So we also specify no =s, no &s and no 
       * spaces
       */ 
      new LuminousDelimiterRule(0, "STRING", 
        LUMINOUS_DYNAMIC_DELIMS|LUMINOUS_COMPLETE|LUMINOUS_EXCLUDE|LUMINOUS_REGEX,
        "/%([wqQx]|(?![=&\s[:alnum:]]))/", null, 
        'luminous_type_callback_ruby_string'),
        
        
      new LuminousDelimiterRule(0, "REGEX", LUMINOUS_REGEX|LUMINOUS_COMPLETE,
      '/
        (?<=([\(\[,=:;\?!~]))
        [\s]* 
        \/
          (?:.*?[^\\\])*?
          (?:\\\\\\\\)*\/
        [iomx]*/x',
        null,
        'luminous_type_callback_generic_string'
      ),
      
      new LuminousDelimiterRule(0, "REGEX",
        LUMINOUS_REGEX|LUMINOUS_DYNAMIC_DELIMS,
        '/%r[\s]*/s', '[iomx]*/', 'luminous_type_callback_generic_string'),
      
      new LuminousDelimiterRule(0, 'HEREDOC', 
        LUMINOUS_REGEX|LUMINOUS_DYNAMIC_DELIMS|LUMINOUS_COMPLETE,
        "/&lt;&lt;(?:\-)?[\"'`]?(.*&lt;&lt;(?:\-)?[\"'`]?)?(?![\s])/",
        null,
        create_function('&$str',
          'luminous_type_callback_generic_heredoc($str);
          luminous_type_callback_cstring($str);
          '))
    );
    $this->simple_types[] = new LuminousSimpleRule(3, 'VARIABLE',
      LUMINOUS_REGEX, "/(?!<[a-z0-9_\\$])(?:@@?|\\$)[a-z0-9_]+/i");
      

    $this->simple_types[] = new LuminousSimpleRule(3, 'VARIABLE',
      LUMINOUS_REGEX, '/
\$
  (?:
    (?:[!@`\'\+1~=\/\\\,;\._0\*\$\?:"])
    |
    (?: &(?:amp|lt|gt); )
    |
    (?: -[0adFiIlpvw])
    |
    (?:DEBUG|FILENAME|LOAD_PATH|stderr|stdin|stdout|VERBOSE)
  )/x');    

    $this->SetSimpleTypeRules();
    $this->simple_types[] = luminous_generic_constant();
    
  }
}

class LuminousGrammarRubyHTML extends LuminousGrammarRuby
{
  
  public function __construct()
  {
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('rhtml');
    $this->SetInfoVersion('0.3.1');
    
    $this->child_grammar = new LuminousGrammarJavaScriptEmbedded();
    $this->ignore_outside = array(
      new LuminousBoundaryRule(LUMINOUS_REGEX,
      "/&lt;%=?/", "/%&gt;/")
    
    );
    $this->keywords[] = "&lt;%=?";
    $this->keywords[] = "%&gt;";
    parent::__construct();
    
  }
}



class LuminousGrammarHTMLText extends LuminousGrammar
{  
  function __construct()
  {
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('htmltext');
    $this->SetInfoVersion('0.3.1');        
    
    $this->simple_types = array(
      new LuminousSimpleRule(4, 'ESC', LUMINOUS_REGEX, 
      "/(?:&amp;)(?:[a-z]+|(#[0-9]+));/i")
      );
  }  
}


class LuminousGrammarHTML extends LuminousGrammar
{
 function __construct()
  {
    
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('html');
    $this->SetInfoVersion('0.3.1');        
    
    $this->ignore_outside = array( 
    new LuminousBoundaryRule(0, "&lt;", "&gt;")
    );
    $this->child_grammar = new LuminousGrammarHTMLText();
    
    $test = true;
    
    $this->delimited_types = array(    
    new LuminousDelimiterRule(0, "COMMENT", LUMINOUS_END_IS_END,
    "&lt;!--", "--&gt;"),
    new LuminousDelimiterRule(0, "COMMENT", LUMINOUS_END_IS_END|LUMINOUS_REGEX,
      "/&lt;!(?!(?i)DOCTYPE)/", "/&gt;/")
    );

    $this->delimited_types[] = new LuminousDelimiterRule(0, "STRING", 
      LUMINOUS_REGEX|LUMINOUS_COMPLETE,
      "/
        (?:'')
        |
        (?:'.*?(?:'|(?=&[lg]t;)))
      /xs");
    
    $this->delimited_types[] = new LuminousDelimiterRule(0, "STRING", 
    LUMINOUS_REGEX|LUMINOUS_COMPLETE,
    '/
    (?:"")|
    (?:".*?(?:"|(?=&gt;)))
    /xs');  
   

    $this->simple_types = array();      
      
    $this->simple_types[] = new LuminousSimpleRule(2, "TYPE", LUMINOUS_REGEX,
      "/(?<=([\s]))(?:[a-z\-:]+)(?=([=]))/i");
    $this->simple_types[] = new LuminousSimpleRule(1, "HTMLTAG", LUMINOUS_REGEX,
      "/(?<=(&lt;))(\/?)[a-z0-9_\-\:]+/i");
    $this->simple_types[] = new LuminousSimpleRule(1, "CONSTANT", 
      LUMINOUS_REGEX, "/(?<=(&lt;))[!?][a-z0-9_\-\:]+/i");    
    $this->simple_types[] = new LuminousSimpleRule(2, 'VALUE', LUMINOUS_REGEX,
      "/(?<=(=))[\s]*[^\s]+/");
  }
}

class LuminousGrammarCSS extends LuminousGrammar
{


  function __construct()
  {
    
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('css');
    $this->SetInfoVersion('0.3.1');        
    
    $this->delimited_types = array(
      luminous_generic_comment('/*', '*/'),
      luminous_generic_string("'", "'"),
      luminous_generic_string("\"", "\"")
      );
      
    
      
    $this->simple_types = array(
      new LuminousSimpleRule(3, 'KEYWORD', LUMINOUS_REGEX,
      "/(?<=^|\}|>)([\s]*)(@?[a-z0-9_\-\s \t\.#:,]*?)(\{)/si", null, 2),
      new LuminousSimpleRule(4, 'VARIABLE', LUMINOUS_REGEX,
        '/(?<=\s)!important/'),
      new LuminousSimpleRule(1, 'NUMERIC', LUMINOUS_REGEX,
      '/(
        \#[a-fA-F0-9]{3,6}
        |
        (?<!\w)\d+(\.\d+)?(em|px|ex|ch|mm|cm|in|pt|%)?
        )/x'),
      new LuminousSimpleRule(3, 'FUNCTION', LUMINOUS_REGEX,
        '/\b(url|rgba?)(?=\()/'),      
      new LuminousSimpleRule(2, "TYPE", LUMINOUS_REGEX, 
      "/[a-zA-Z\-]+[\s]*(?=[:])/"),
      new LuminousSimpleRule(2, "VALUE", LUMINOUS_REGEX, 
        "/(?<=[:])[\s]*.+?(?=[;\}$])/s"),


      
      new LuminousSimpleRuleList(4, "OPERATOR", 0, 
        array(';', ':', '#', '.', '{', '}'))
      );
  }
}


class LuminousGrammarCSSEmbedded extends LuminousGrammarCSS
{

  function __construct()
  {
    $this->ignore_outside = array(
      new LuminousBoundaryRule(LUMINOUS_REGEX|LUMINOUS_EXCLUDE, 
      "/(&lt;style.*?&gt;)/si", "/(&lt;\/style&gt;)/si")
      );
    $this->child_grammar = new LuminousGrammarHTML();
   
    parent::__construct();
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoVersion('0.3.1');          
  }
}

class LuminousGrammarJavaScript extends LuminousGrammar
{
  public $keywords =  array("break", "c(ase|atch|omment|ontinue)", 
    "d(efault|elete|o)", "e(lse|xport)",
    "f(or|unction)", "i(f|mport|n)",   "label", "return",  "switch",  "try",  
    "void", "w(hile|ith)");    
  
  public $functions = array('\$', 'encodeURI(?:Component)?', 
    'decodeURI(?:Component)?', 'parseInt', 'parseFloat', 'isNaN', 'isFinite', 
    'eval', 'alert', 'confirm', 'prompt', 'Array', 'Boolean', 'Date', 'Error', 
    'EvalError', 'Number', 'Object', 'RangeError', 'ReferenceError', 'RegExp', 
    'String', 'SyntaxError', 'TypeError', 'URIError');
  
  public $types = array('this', 'var', 'Infinity', 'Math', 'NaN', 'true', 
    'false', 'undefined', 'null', 'String', 'Date', 'Array', 'Object', 'Image', 
    'Option');
  
  public $oo_separators = array('\.');

  public function __construct()
  {
    
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('js');
    $this->SetInfoVersion('0.3.1');    
    
    $this->operators = array_merge($this->operators,
    array('\?', '\:', '(?<![a-zA-Z0-9_])delete(?![a-zA-Z0-9_])', 
    '(?<![a-zA-Z0-9_])get(?![a-zA-Z0-9_])', 
    '(?<![a-zA-Z0-9_])in(stanceof)?(?![a-zA-Z0-9_])', 
    '(?<![a-zA-Z0-9_])let(?![a-zA-Z0-9_])', 
    '(?<![a-zA-Z0-9_])new(?![a-zA-Z0-9_])', 
    '(?<![a-zA-Z0-9_])set(?![a-zA-Z0-9_])',
    '(?<![a-zA-Z0-9_])typeof(?![a-zA-Z0-9_])', 
    '(?<![a-zA-Z0-9_])void(?![a-zA-Z0-9_])', 
    '(?<![a-zA-Z0-9_])yield(?![a-zA-Z0-9_])'));
      
    
    $this->delimited_types = array(
      luminous_generic_doc_comment('/**', '*/'),
      luminous_generic_doc_comment('/*!', '*/'),
      luminous_generic_doc_comment('//!', "\n"),
      luminous_generic_doc_comment('///', "\n"),
      
      luminous_generic_comment('/*', '*/'),                               
      new LuminousDelimiterRule(0, 'COMMENT', LUMINOUS_STOP_AT_END, '//', "\n"),
      luminous_generic_string('"', '"'),
      luminous_generic_string("'", "'"),
      luminous_generic_regex('igm')
      
      // I can't decide which is faster.
      
// //       new LuminousDelimiterRule("REGEX", LUMINOUS_REGEX,
// //         '/
// //           (?<=([\(\[,=:;\?!]))
// //           [\s]* 
// //           \/[^\/\*]
// //           /x', '/\/[igm]*/')
//       
//       new LuminousDelimiterRule("REGEX", LUMINOUS_REGEX|LUMINOUS_COMPLETE, 
//         '/
//         (?<=([\(\[,=:;\?!\|\&]))
//         [\s]* 
//         \/(?![\/\*])
//         (?:.*?[^\\\])*?
//         (?:\\\\\\\\)*\/
//         [igm]*/x',
//         null,
//         'luminous_type_callback_generic_string'
//       )
    );


    $this->SetSimpleTypeRules();
    $this->simple_types[] = luminous_generic_constant();
    
  }
  
  
}


class LuminousGrammarJavaScriptEmbedded extends LuminousGrammarJavaScript
{

  function __construct()
  {    
    $this->ignore_outside = array(
      new LuminousBoundaryRule(LUMINOUS_REGEX|LUMINOUS_EXCLUDE,
      "/(?:&lt;script.*?&gt;)/si", "/(?:&lt;\/?script&gt;)/si")
      );    
    $this->child_grammar = new LuminousGrammarCSSEmbedded();
    
    parent::__construct();
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoVersion('0.3.1');          
    
  }
}



class LuminousGrammarBash extends LuminousGrammar
{
  
  function __construct()
  {
    
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('sh');
    $this->SetInfoVersion('0.3.1');        
    
    $this->keyword_regex = '/(?<![a-zA-Z0-9_$\.])(?:%KEYWORD)(?![a-zA-Z0-9_\.])/';
    
    
    $this->numeric_regex = '
    /(?<![[:alnum:]_<$\.\-])  
    (
      #hex 
      (?:0[xX][0-9A-Fa-f]+)
    |
      # regular number
      (?:
        [0-9]+
        (?:
          # fraction
          \.[0-9]+([eE]?[0-9]+)?
        )?
      )
      |
      (?:
        # or only after the point, float x = .1;
        \.[0-9]+(?:[eE]?[0-9]+)?
      )
    )
    (?![[:alnum:]_<$\.\-]) 
    /x';
    
    
    $this->keywords = array_merge($this->keywords, 
      array("case", "do", "done", "elif", "else", "esac", "fi", "for",
    "function", "if", "in", "select", "then", "time", "until", "while")
    );
    
    $this->operators = array();
    
    // just some common ones or I'll be here all year.
    $this->functions = array("awk", "cat", 'cd', "chmod", "chown", "cp", "cut", 
      "date", "diff", "echo", "egrep", "env", "eval", "exit", "export", "file",
      "find", "ftp", "gawk", "grep", "gzip", "head", "help", 'join', 'less', 
      'ln', 'ls', 'mkdir', 'mv', 'ps', 'pwd', 'read', 'rename', 'rm', 'rmdir', 
      'sed', 'sleep', 'sort', 'ssh', 'sudo', 'su', 'tail', 'tar', 'time',
      'touch'); 
    
    $this->delimited_types = array(
      luminous_generic_shebang(),
      new LuminousDelimiterRule(0, 'COMMENT', LUMINOUS_REGEX|LUMINOUS_COMPLETE,
      '/(?<!\$)#.*$/m'),
      luminous_generic_string('"', '"', 'luminous_type_callback_bash_string'),
      luminous_generic_string("'", "'", 'luminous_type_callback_bash_string'),

      //obviously these are function calls, but it looks prettier if they're not.
      // and it's easier to read. Perhaps need a new identifier.
      new LuminousDelimiterRule(0, "TYPE", LUMINOUS_REGEX|LUMINOUS_COMPLETE,
      '/\$\([^\(]+\)/', null, 'luminous_type_callback_bash_string'),
      
      new LuminousDelimiterRule(0, 'FUNCTION', 0, '`', '`',
        'luminous_type_callback_bash_string'),
        
      new LuminousDelimiterRule(0, 'HEREDOC', 
        LUMINOUS_COMPLETE|LUMINOUS_DYNAMIC_DELIMS|LUMINOUS_REGEX, 
        '/(?:&lt;){2}[\-\\\]?/', null,
        create_function('&$str', 
        'luminous_type_callback_generic_heredoc($str);
        luminous_type_callback_bash_string($str);
        '))
      );
      
    $this->simple_types[] =     
      new LuminousSimpleRule(3, "VARIABLE", LUMINOUS_REGEX,
        '/[[:alnum:]_-]*?[\s]*(?=[=])/m');
    $this->simple_types[] =     
        new LuminousSimpleRule(3, "VARIABLE", LUMINOUS_REGEX,
        '/\${.*?}/m');
        
    $this->simple_types[] =         
      new LuminousSimpleRule(3, 'VARIABLE', LUMINOUS_REGEX,
        "/\\$(?:(?:[[:alnum:]_-]+)|[#\*\?])/");
        
    // yes this again. ./
    $this->simple_types[] = 
      new LuminousSimpleRule(2, 'TYPE', LUMINOUS_REGEX, 
        '/(?<![[:alnum:]_\$\.])\.\/.*?[^\s]([\s]|$)/');
         
    $this->SetSimpleTypeRules();
  }
}

class LuminousGrammarMakefile extends LuminousGrammarBash
{
  function __construct()
  {
    
    $this->keywords[] = "endif";
    $this->keywords[] = "ifdef";
    
    // dependency
    $this->simple_types[] = new LuminousSimpleRule(3, 'MAKE_DEP', LUMINOUS_REGEX,
    '/(^[[:alnum:]_\-\. ]+?:)(.*?$)/m', null, 2);
      
//     // Makefile make Rule.
    $this->simple_types[] = 
      new LuminousSimpleRule(3, 'MAKE_TARGET', LUMINOUS_REGEX, 
        '/^[[:alnum:]_\-\. \t]+?(?=:)/m');
    parent::__construct();
    
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoVersion('0.3.1');
        
  }
  
  
}





class LuminousGrammarPlain extends LuminousGrammar
{
  
  function __construct()
  {
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
                         'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('plain');
    $this->SetInfoVersion('0.3.1');      
    
    $this->simple_types = array(
      new LuminousSimpleRule(0, 'COMMENT', LUMINOUS_REGEX,
      '/^[\s]*[#;].*$/m'),

      new LuminousSimpleRule(3, 'VALUE', LUMINOUS_REGEX,
      '/(^[[:alnum:]_ \t]+?=)(.*)/m', null, 2),
      new LuminousSimpleRule(2, 'VARIABLE', LUMINOUS_REGEX,
      '/^[[:alnum:]_ \t]*?(?=[=])/m'),
      new LuminousSimpleRule(2, 'KEYWORD', LUMINOUS_REGEX,
      '/^([ \t]*)(\[)(.+?)(\])/im'),
      new LuminousSimpleRule(4, 'OPERATOR', 0, '=')
      
      );
  }
  
  public function SetRuleset(&$str)
  {
    
  }
  
}

class LuminousGrammarMATLAB extends LuminousGrammar
{

  public $keywords = array('break', 'case', 'catch', 'classdef', 'continue',
    'else', 'elseif','end', 'for', 'function', 'global', 'if', 'otherwise', 
    'parfor', 'persistent', 'return', 'spmd', 'switch', 'try', 'while');
    
  public $functions  = array(
    
    // Maths functions
    //  http://www.mathworks.co.uk/help/techdoc/ref/f16-5872.html    
    'disp','display',
    'is(?:column|empty|equalwithequalnans|finite|float|inf|integer|logical|matrix|nan|numeric|row|scalar|sparse|vector)',
    'length', 'max', 'min', 'ndims', 'numel', 'size', 'blkdiag', 'diag', 
    'eye', 'freqspace', 'ind2sub', 'linspace', 'logspace', 'meshgrid',
    'ndgrid', 'ones', 'rand[ni]?', 'RandStream', 'sub2ind', 'zeros',
    'accumarray', 'arrayfun', 'bsxfun', 'cast', 'cross', 'cumprod', 'cumsum',
     'dot', 'idivide', 'kron', 'prod', 'sum', 'surfnorm', 'tril', 'triu',
     'blkdiag', 'cat', 'circshift', 'diag', 'end', 'flipdim', 'fliplr',
     'flipud', 'horzcat', 'inline', 'ipermute', 'permute', 'repmat',
     'reshape', 'rot90', 'shiftdim', 'sort', 'sortrows', 'squeeze',
     'vectorize', 'vertcat', 'compan', 'gallery', 'hadamard', 'hankel',
     'hilb', 'invhilb', 'magic', 'pascal', 'rosser', 'toeplitz', 'vander',
     'wilkinson', 'cond', 'condeig', 'det', 'norm', 'normest', 'null', 'orth',
     'rank', 'rcond', 'rref', 'subspace', 'trace', 'chol', 'cholinc', 'cond',
    'condest', 'funm', 'ilu', 'inv', 'ldl', 'linsolve', 'lscov', 'lsqnonneg',
    'lu', 'luinc', 'pinv', 'qr', 'rcond', 'balance', 'cdf2rdf', 'condeig', 
    'eigs?', 'gsvd', 'hess', 'ordeig', 'ordqz', 'ordschur', 'poly(?:eig)?',
    'rsf2csf', 'schur', 'sqrtm', 'ss2tf', 'svds?', 'expm', 'logm', 'sqrtm',
    'balance', 'cdf2rdf', 'chol(?:inc|update)', 'gsvd', 'ilu', 'ldl', 'lu',
    'luinc', 'planerot', 'qr(?:delete|insert|update)', 'qz', 'rsf2csf',
    'acos[dh]?', 'acot[dh]?', 'acsc[dh]?', 'asec[dh]?', 'asin[dh]?', 
    'atan[2dh]?', 'cos[dh]?', 'cot[dh]?', 'csc[dh]?', 'hypot', 'sec[dh]?',
    'sin[dh]?', 'tan[dh]', 'exp(?:m1)?', 'log(10|1p|2)?', 'nextpow2',
    'nthroot', 'pow2', 'power', 'real(?:log|pow|sqrt)', 'sqrt', 'abs',
    'angle', 'complex', 'conj', 'cplxpair', 'imag', 'isreal', 'real', 'sign',
    'unwrap', 'Rounding', 'ceil', 'fix', 'floor', 'idivide', 'mod', 'rem',
     'round', 'factor', 'factorial', 'gcd', 'isprime', 'lcm', 'nchoosek',
     'perms', 'primes', 'rats?', 'conv', 'deconv', 'poly(der|eig|fit|int|valm?)?',
    'residue', 'roots', 'dsearch', 'dsearchn', 'griddata', 'griddata3',
    'griddatan', 'interp(1q?|[23])', 'interpft', 'interpn', 'meshgrid',
    'mkpp', 'ndgrid', 'padecoef', 'pchip', 'ppval', 'spline',
    'TriScatteredInterp', 'tsearch', 'tsearchn', 'unmkpp', 'baryToCart',
    'cartToBary', 'circumcenters', 'delaunay[3n]?', 'DelaunayTri',
    'edgeAttachments', 'edges', 'faceNormals', 'featureEdges',
    'freeBoundary', 'incenters', 'inOutStatus', 'isEdge', 'neighbors',
    'size', 'tetramesh', 'tri(?:mesh|plot|surf)', 'vertexAttachments',
    'convexHull', 'convhulln?', 'patch', 'trisurf', 'Voronoi', 'patch',
    'voronoi(?:Diagram|n)?', 'meshgrid', 'ndgrid', 'cart2(pol|sph)',
    'pol2cart', 'sph2cart', 'decic', 'deval', 'ode\d+[stb]*',
    'ode(?:file|get|set|extend)', 'dde(?:23|[sg]et|sd)', 'deval', 'bvp[45]c',
    'bvp(?:[sg]et|init|xtend)', 'deval', 'pdepe', 'pdeval', 'fminbnd',
    'fminsearch', 'fzero', 'lsqnonneg', 'optim[sg]et', 'dblquad',
    'quad(?:2d|gk|l|v)?', 'triplequad', 'airy', 'bessel[hijky]', 
    'beta(?:inc(?:inv)?)?', 'betaln', 'ellip(?:j|ke)', 'erfc(?:inv|x|inv)',
    'erfinv', 'expint', 'gamma(?:inc|incinv|ln)', 'legendre', 'psi',
    'sp(diags|eye|randn?|randsym)', 'find', 'full', 'sparse', 'spconvert',
    'issparse', 'nnz', 'nonzeros', 'nzmax', 'sp(alloc|fun|ones|parms|y)', 
    'amd', 'colamd', 'colperm', 'dmperm', 'ldl', 'randperm', 'symamd',
    'symrcm', 'cholinc', 'condest', 'eigs', 'ilu', 'luinc', 'normest',
    'spaugment', 'sprank', 'svds', 'bicg(?:stabl?)?', 'cgs', 'gmres', 'lsqr',
    'minres', 'pcg', 'qmr', 'symmlq', 'tfqmr', 'etree', 'etreeplot', 'gplot',
    'symbfact', 'treelayout', 'treeplot', 'unmesh',
    
    // Data conversion
    // http://www.mathworks.com/help/techdoc/ref/f16-42340.html#f16-52710
    'cast', 'double', 'int(?:8|16|32|64)', 'single', 'typecast', 
    'uint(?:8|16|32|64)', 'base2dec', 'bin2dec', 'hex2(?:dec|num)', 
    'str2(?:double|num)', 'unicode2native', 'char', 'dec2(?:base|bin|hex)',
    'int2str', 'mat2str',  'native2unicode', 'num2str', 'cell2(?:mat|struct)',
    'datestr', 'func2str', 'logical', 'mat2cell', 'num2(?:cell|hex)',
    'str2(?:func|mat)', 'struct2cell'
    
    );
    
    
    public $types = array('eps', 'i', 'Inf', 'int(?:max|min)', 'j', 'NaN', 'pi',
      'real(?:max|min)');
    
    
  public function __construct()
  {
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('matlab');
    $this->SetInfoVersion('0.3.1');    
    
    
    $this->delimited_types = array(
      new LuminousDelimiterRule(0, 'COMMENT', LUMINOUS_COMPLETE|LUMINOUS_REGEX,
      '/%\{ (.*? (?R)* .*?)* \}%/sx'),
      luminous_generic_comment( "%", "\n")
      ,
      new LuminousDelimiterRule(0, 'STRING', LUMINOUS_COMPLETE|LUMINOUS_REGEX,
      $regex = "/
        (?<![a-zA-Z0-9\)\]\}_])
        (?:'')
        |
        (?:(?:'.*?(?<!')')(?!'))
      /sx", null, 'luminous_type_callback_sql_single_quotes')
      );
    
    $this->SetSimpleTypeRules();    
    
  }
}


class LuminousGrammarCSharp extends LuminousGrammar
{
  public $keywords = array("abstract", "event", "new", "struct", "as", 
    "explicit", "null", "switch", "base", "extern", "object", "this", "false", 
    "operator", "throw", "break", "finally", "out", "true","fixed", "override", 
    "try", "case", "params", "typeof", "catch", "for", "private", "foreach", 
    "protected", "checked", "goto", "public", "unchecked", "class", "if", 
    "readonly", "unsafe", "implicit", "ref", "continue", "in", "return", 
    "using", "decimal", "virtual", "default", "interface", "sealed", "volatile",
    "delegate", "internal", "void", "do", "is", "sizeof", "while", "lock", 
    "stackalloc", "else", "long", "static", "enum", "namespace");
  
  public $types = array("bool", "byte", "char", "const", "double", "float", "int",
  "long", "sbyte", "short", "uint", "ulong", "ushort", "string",
  // system namespace
  "Array", "Attribute", "Byte", "Buffer", "Char", "DateTime", "Double", "EventArgs",
  "EventHandler", "Exception", "U?Int(?:16|32|64|Ptr)", "Object", "String", "Tuple",
  "Type",
  // system.collection namespace
  "ArrayList", "I?Comparer", "I?Dictionary", "Hashtable", "Hashset", "I?List", 
  "I?Set", "Queue", "SortedList", "Stack",
  
  //System.IO
  "Binary(?:Reader|Writer)", "BufferedStream", 
  "Directory(?:Info|NotFoundException)?", "Drive(?:Info|NotFoundException)?", 
  "EndOfStreamException", "ErrorEvent(?:Args|Handler)", 
  "File(?:Access|Attributes|FormatException|Info|LoadException|Mode|NotFoundException|Options|Share|Stream|SystemEventArgs|SystemEventHandler|SystemInfo|SystemWatcher)?", 
  "HandleInheritability", "InternalBufferOverflowException", 
  "InvalidDataException", "IODescriptionAttribute", "IOException", 
  "MemoryStream", "NotifyFilters", "Path(?:TooLongException)?", 
  "PipeException", "RenamedEventArgs", "RenamedEventHandler", "SearchOption", 
  "SeekOrigin", "Stream(?:Reader|Writer)?", "String(?:Reader|Writer)", 
  "Text(?:Reader|Writer)", "UnmanagedMemory(?:Accessor|Stream)", 
  "WaitForChangedResult", "WatcherChangeTypes",
  
  // module things
  "System(?:[\w\.]*)?",
  "Accessibility",
  "Microsoft(?:[\w\.]*)?",
  "UIAutomationClientsideProviders",
  "XamlGeneratedNamespace"
  );
  
  public $functions = array("get", "set");
  
  public $oo_separators = array('\.');
  
 function __construct()
  {
    
    
    $this->SetInfoAuthor( 
      array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
      'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('cs');
    $this->SetInfoVersion('0.3.1');    
    
    
    $this->delimited_types = array(
      new LuminousDelimiterRule(0, 'PREPROCESSOR', LUMINOUS_REGEX|LUMINOUS_COMPLETE,
      '/#.*?[^\\\](\\\\)*$/sm'),
      luminous_generic_doc_comment('/**', '*/'),
      luminous_generic_doc_comment('/*!', '*/'),
      luminous_generic_doc_comment('//!', "\n"),
      luminous_generic_doc_comment('///', "\n"),
      
      luminous_generic_comment('/*', '*/'),
      luminous_generic_comment('//', "\n"),
      luminous_generic_string(),
      
      new LuminousDelimiterRule(0, 'CHARACTER', 0, '\'', '\'',
      'luminous_type_callback_cstring'),
    );
    
    $this->SetSimpleTypeRules();
    $this->simple_types[] = luminous_generic_constant();
    
  }

}


class LuminousGrammarJava extends LuminousGrammar
{
  public $keywords = array("abstract", "continue", "for", "new", "switch",
    "assert", "default", "goto", "package", "synchronized",
    "do", "if", "private", "this",
    "break", "implements", "protected", "throw",
    "else", "import", "public", "throws",
    "case", "enum", "instanceof", "return", "transient",
    "catch", "extends", "try",
    "final", "interface", "static", "void",
    "class", "finally", "strictfp", "volatile",
    "float", "native", "super", "while");

  public $types = array("byte", "const", "char", "double", "float", "int",
  "short", "long", "bool(ean)?", "String", "Boolean", "Byte", "Character", "Class",
  "Double", "Float", "Integer", "Long", "Number", "Object", "Package", 
  "Short", "StringBuffer", "Thread", "Void", "Exception",
  "Abstract(?:Collection|List|Map|SequentialList|Set)",
  "Array(?:List|s)",
  "BitSet",
  "Calendar",
  "Collections",
  "Currency",
  "Date",
  "Dictionary",
  "EventListenerProxy",
  "EventObject",
  "GregorianCalendar",
  "Hash(?:Map|Set|table)",
  "IdentityHashMap",
  "Linked(?:Hash(?:Map|Set)|List)",
  "ListResourceBundle",
  "Locale",
  "Observable",
  "Properties",
  "Property(?:Permission|ResourceBundle)",
  "Random",
  "ResourceBundle",
  "SimpleTimeZone",
  "Stack",
  "StringTokenizer",
  "Timer(?:Task)?",
  "TimeZone",
  "Tree(?:Map|Set)",
  "Vector",
  "WeakHashMap"
  
  );
  public $oo_separators = array('\.');
  function __construct()
  {
    
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('java');
    $this->SetInfoVersion('0.3.1');        
    
    $this->delimited_types = array(
      
      luminous_generic_doc_comment('/**', '*/'),
      
      luminous_generic_comment('/*', '*/'),
      luminous_generic_comment('//', "\n"),
      
      luminous_generic_string(),
      
      new LuminousDelimiterRule(0, 'CHARACTER', 0, '\'', '\'',
      'luminous_type_callback_cstring')      
      
      );
    
    $this->simple_types[] = new LuminousSimpleRule(3, 'TYPE', LUMINOUS_COMPLETE
      |LUMINOUS_REGEX, '/(?:(?<=import)|(?<=package))(\s+)([\w\.\*]+)/', null, null, 2);
    $this->SetSimpleTypeRules();
    $this->simple_types[] = luminous_generic_constant();
    
      
  }
}


/** Normal Diff */
class LuminousGrammarDiff extends LuminousGrammar
{

  
  function __construct()
  {
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('diff');
    $this->SetInfoVersion('0.3.1');        
    
    $this->simple_types = array(
      new LuminousSimpleRule(1, 'DIFF_RANGE', LUMINOUS_REGEX, 
        '/^[0-9]+(?:,[0-9]+)?[acd]?[0-9]+(,[0-9]+)?$/mi'),
      new LuminousSimpleRule(0, 'DIFF_OLD', LUMINOUS_REGEX,
        '/^&lt;.*$/mi'),
      new LuminousSimpleRule(0, 'DIFF_NEW', LUMINOUS_REGEX,
        '/^\&gt;.*$/mi')
    );
    
  }
}


/** Unified Diff */
class LuminousGrammarUDiff extends LuminousGrammar
{

  
  function __construct()
  {
    
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('udiff');
    $this->SetInfoVersion('0.3.1');        
    
    $this->simple_types = array(
      new LuminousSimpleRule(1, 'DIFF_HEADER_NEW', LUMINOUS_REGEX,
        '/^\+{3}.*$/mi'),
        
      new LuminousSimpleRule(1, 'DIFF_HEADER_OLD', LUMINOUS_REGEX,
       '/^\-{3}.*$/mi'),        
        
      new LuminousSimpleRule(1, 'DIFF_RANGE', LUMINOUS_REGEX, 
        '/^@@.*@@$/mi'),
        
      new LuminousSimpleRule(0, 'DIFF_OLD', LUMINOUS_REGEX,
        '/^\-[^\-].*$/mi'),
        
      new LuminousSimpleRule(0, 'DIFF_NEW', LUMINOUS_REGEX,
       '/^\+[^\+].*$/mi')
    );
    
  }  
}


class LuminousGrammarHaskell extends LuminousGrammar
{

  public $keywords = array("as", "case", "of", "class", "data", "family",
    "instance", "default", "deriving", "do", "forall", "foreign", "hiding",
    "if", "then", "else", "import", "infix", "infixl", "infixr", "let", "in",
    "mdo", "module", "newtype", "proc", "qualified", "rec", "type", "where");
    
  public $types = array("Integer", "Char", "String", "Float");
  
  // Haskell's philosophy seems to be "you've got all those keys on your
  // keyboard and I'm not going to waste them"
  public $operators = array('\+', '\*', '-', '\/', '=', '&gt;', '&lt;', '=',
  '!', '%', '&amp;', '\|', '~', '\^', '\[', '\]', '\(', '\)', '\.', ':', '@'
  );
  
  public function __construct()
  {
    
    
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('hs');
    $this->SetInfoVersion('0.3.1');        
    
    
    
    $this->delimited_types = array(
      luminous_generic_string('"', '"'),
      new LuminousDelimiterRule(0, "CHARACTER", LUMINOUS_REGEX|LUMINOUS_COMPLETE,
        "/'(\\\\)?.'/"),
      new LuminousDelimiterRule(0, "FUNCTION", 0, "`", "`"),
      new LuminousDelimiterRule(0, "FUNCTION", LUMINOUS_REGEX|LUMINOUS_COMPLETE,
      "/\\\\.*?[\s]/"),
      luminous_generic_comment('--', "\n"),
      
      new LuminousDelimiterRule(0, "COMMENT", LUMINOUS_REGEX|LUMINOUS_COMPLETE,
      '/\{- ( .*? (?R)* .*?)* -\}/sx'
      // old code.
//       // Haskell's comments can be nested which is all very nice but 
//       // I think that it's computationally impossible to validate arbtrary 
//       // depth bracket nesting with a regex.
//       // This one goes to depth 2.
//       "/
//       \{\-
//         (?:.*?
//         (?:\{\-.*?\-\})?
//         )*?
//       \-\}
//       /xs"
      )
      );    
      
    $this->SetSimpleTypeRules();  
  }
  
}




class LuminousGrammarSQL extends LuminousGrammar
{
  
  public $keyword_regex =  "/(?<![a-zA-Z0-9_$])%KEYWORD(?![a-zA-Z0-9_])/i";
  public $keywords = array("ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER",
  "ANALYZE", "AND", "AS", "ASC", "ATTACH", "AUTO(?:_)?INCREMENT", "BEFORE", "BEGIN",
  "BETWEEN", "BY", "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN",
  "COMMIT", "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE",
  "CURRENT_TIME", "CURRENT_TIMESTAMP", "DATABASE", "DEFAULT", "DEFERRABLE",
  "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DROP", "EACH", "ELSE",
  "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN", "FAIL", "FOR",
  "FOREIGN", "FROM", "FULL", "GLOB", "GROUP", "HAVING", "IF", "IGNORE",
  "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER", "INSERT",
  "INSTEAD", "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY", "LEFT",
  "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", "NOTNULL", "NULL", "OF",
  "OFFSET", "ON", "OR", "ORDER", "OUTER", "PLAN", "PRAGMA", "PRIMARY", "QUERY",
  "RAISE", "REFERENCES", "REGEXP", "REINDEX", "RELEASE", "RENAME", "REPLACE",
  "RESTRICT", "RIGHT", "ROLLBACK", "ROW", "SAVEPOINT", "SELECT", "SET", "TABLE",
  "TEMP", "TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNION", "UNIQUE",
  "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE");
  
  public $type_regex =  "/(?<![a-zA-Z0-9_$])(:?%TYPE)(?![a-zA-Z0-9_])/i";
  
  public $types = array("(?:tiny|small|medium|big)?int(?:eger)?", "(?:var)?char",
  "(?:tiny|medium|long)?text", "(?:long)?blob", "float", "double", "decimal", 
  "data(?:time)?", "time(?:stamp)?");
  
  
  public function __construct()
  {
    
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('sql');
    $this->SetInfoVersion('0.3.1');        
    
    
    $this->delimited_types = array(
      new LuminousDelimiterRule(0, "COMMENT", 0, "--", "\n"),        
      new LuminousDelimiterRule(0, "STRING", LUMINOUS_REGEX|LUMINOUS_COMPLETE, 
        "/
        (?:'')
        |
        (?:(?:'.*?(?<!')')(?!'))
        /sx", null, 'luminous_type_callback_sql_single_quotes'),
      new LuminousDelimiterRule(0, "STRING", 0, "`", "`",
        'luminous_type_callback_generic_string'),
      new LuminousDelimiterRule(0, "STRING", 0, '"', '"',
        'luminous_type_callback_generic_string')
      );
      
    $this->SetSimpleTypeRules();
    
    
  }

}

///\todo: named operators.
///\todo: variable interpolation
class LuminousGrammarPerl extends LuminousGrammar
{
  public $keywords = array("my", "print",
     "caller",
     "continue",
     "die",
     "do",
     "dump",
     "else",
     "elsif",
     "eval",
     "exit",
     "for",
     "foreach",
     "goto",
     "import",
     "if",
     "last",
     "local",
     "next",
     "prototype",
     "redo",
     "return",
     "sub",
     "use",
     "wantarray",
     "while");
 
  public $ignore_outside_strict = false;
  
  public $oo_separators = array('::', '-&gt;');
  
  
  
  public function __construct()
  {
    
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('pl');
    $this->SetInfoVersion('0.3.1');   
    
    
    
    $this->delimited_types = array(
      new LuminousDelimiterRule(0, 'SHEBANG', LUMINOUS_REGEX|LUMINOUS_COMPLETE, 
      "/^[\s]*#!.*?\n/"),
      new LuminousDelimiterRule(0, "FUNCTION", 0, '`', '`'),
      new LuminousDelimiterRule(0, "COMMENT", LUMINOUS_REGEX|LUMINOUS_COMPLETE, 
      '/(?<![%@\$])#.*/', null),
      new LuminousDelimiterRule(0, "STRING", LUMINOUS_EXCLUDE, '"', '"',
      'luminous_type_callback_perl_string'),
      new LuminousDelimiterRule(0, "STRING", LUMINOUS_EXCLUDE, '\'', '\''),
      
      new LuminousDelimiterRule(0, "STRING",       
        LUMINOUS_REGEX|LUMINOUS_DYNAMIC_DELIMS|LUMINOUS_COMPLETE|LUMINOUS_EXCLUDE,
        '/(?<![a-zA-Z0-9_\$])q[qxw]?[\s]*(?![a-zA-Z0-9])/',
        null, 'luminous_type_callback_perl_string'),
        new LuminousDelimiterRule(0, "VALUE", LUMINOUS_REGEX|LUMINOUS_COMPLETE,
       "/&lt;(STDIN|STDOUT|STDERR|DATA)&gt;/"),
       
       // I don't know if these next two are right.
       new LuminousDelimiterRule(0, "REGEX", LUMINOUS_REGEX|LUMINOUS_COMPLETE,
        '/
          (?<=([\(\[,=:;\?!~]))
          [\s]* 
          (?:m|qr)?\/
            (?:.*?[^\\\])*?
          (?:\\\\\\\\)*\/
          [cgimosx]*/x', null, 'luminous_type_callback_generic_string'),        
      
          new LuminousDelimiterRule(0, "REGEX", LUMINOUS_REGEX|LUMINOUS_COMPLETE,
        '/
          (?<=([\(\[,=:;\?!~]))
          [\s]* 
          (?:s|tr|y)\/
            (?:(.*?[^\\\])*?
          (?:\\\\\\\\)*\/){2}
          [cdsegimosx]*/x',       
        null, 'luminous_type_callback_generic_string'),
        
        new LuminousDelimiterRule(0, 'HEREDOC', 
          LUMINOUS_COMPLETE|LUMINOUS_REGEX|LUMINOUS_DYNAMIC_DELIMS,
          '/(?:&lt;){2}["`]?(?=[[:alnum:]])/', null,
          create_function('&$str', 
          'luminous_type_callback_perl_string($str);
            luminous_type_callback_generic_heredoc($str);')),
          
        new LuminousDelimiterRule(0, 'HEREDOC', 
          LUMINOUS_COMPLETE|LUMINOUS_REGEX|LUMINOUS_DYNAMIC_DELIMS,
          '/(?:&lt;){2}[\']?(?=[[:alnum:]])/',
          null,
          'luminous_type_callback_generic_heredoc')          
       );       

    $this->ignore_outside = array( 
      new LuminousBoundaryRule(LUMINOUS_REGEX, "/^/", 
      "/__(DATA|END)__/")
      );
      
      
      // this isn't really a type, but what else do you call it?
      $this->simple_types[] = new LuminousSimpleRule(3, 'TYPE',
        LUMINOUS_REGEX, '/&lt;[[:alnum:]_]+&gt;/');
      
      
      $this->simple_types[] = new LuminousSimpleRule(3, 'VARIABLE',
        LUMINOUS_REGEX, "/(?!<[a-z0-9_])[$%@][a-z0-9_]+/i");
        
/*      $this->simple_types[] = new LuminousSimpleRule(3, 'VALUE',
        LUMINOUS_REGEX, "/(?<=::)(?>[a-z0-9_]+)[\s]*(?!\()/i");      */  
      
      
      $this->SetSimpleTypeRules();
      $this->simple_types[] = luminous_generic_constant();
      
        

      $this->simple_types[] = new LuminousSimpleRule(3, 'VALUE',
        LUMINOUS_REGEX, "/__(DATA|END)__/");  
        
  }
  

}

class LuminousGrammarPHP extends LuminousGrammar
{

  public $operators = array('\+', '\*', '-', '\/', '=', '&gt;', 
    '&lt;', '=', '!', '%', '&amp;', '\|', '~', '\^', '\[', '\]');
  
//   public $keywords = array(
//   "&lt;\?(?:php)?", "\?&gt;",
//   "abstract", "and",  "as", "break",
//   "case", "catch", "cfunction", "class", "Class", "clone",
//   "const", "continue", "declare", "default", "do",
//   "echo","else", "elseif", "enddeclare", "endfor", "endforeach",
//   "endif", "endswitch", "endwhile", "extends", "final",
//   "for", "foreach", "function", "global", "goto",
//   "if", "implements", "interface", "instanceof",
//   "namespace", "new", "old_function", "or", "private",
//   "protected", "public", "return", "static", "switch", "throw",
//   "try", "use", "var", "while", "xor" );
  
  
  public $keywords = array("&lt;\?(?:php)?", "\?&gt;", 'Class', 'a(?:(?:bstract)|(?:nd)|(?:s))', 'break', 'c(?:(?:a(?:(?:se)|(?:tch)))|(?:function)|(?:l(?:(?:ass)|(?:one)))|(?:on(?:(?:st)|(?:tinue))))', 'd(?:(?:e(?:(?:clare)|(?:fault)))|(?:o))', 'e(?:(?:cho)|(?:lse(if)?)|(?:nd(?:(?:declare)|(?:foreach)|(?:if)|(?:switch)|(?:while)))|(?:xtends))', 'f(?:(?:inal)|(?:or(each)?)|(?:unction))', 'g(?:(?:lobal)|(?:oto))', 'i(?:(?:f)|(?:mplements)|(?:n(?:(?:stanceof)|(?:terface))))', 'n(?:(?:amespace)|(?:ew))', 'o(?:(?:ld_function)|(?:r))', 'p(?:(?:r(?:(?:ivate)|(?:otected)))|(?:ublic))', 'return', 's(?:(?:tatic)|(?:witch))', 't(?:(?:hrow)|(?:ry))', 'use', 'var', 'while', 'xor',
  '\$this', 'parent');
    

  public $function_regex =  '/(?<![a-zA-Z0-9_$])(?:%FUNCTION)(?![a-zA-Z0-9_])/x';     
  public $functions = array("include(?:_once)?", "require(?:_once)?",
    // array functions
    'array(_
    (?:(?:change_key_case)|
    (?:chunk)|
    (?:combine)|
    (?:count_values)|
    (?:diff(?:_(?:u?assoc|u?key))?)|
    (?:fill(?:_keys)?)|
    (?:filter)|
    (?:flip)|
    (?:intersect(?:_(?:u?assoc|u?key))?)|
    (?:key(?:s|_exists))|
    (?:map)|
    (?:merge(?:_recursive)?)|
    (?:multisort)|
    (?:pad)|
    (?:pop)|
    (?:product)|
    (?:push)|
    (?:rand)|
    (?:reduce)|
    (?:replace(?:_recursive)?)|
    (?:reverse)|
    (?:search)|
    (?:shift)|
    (?:slice)|
    (?:splice)|
    (?:sum)|
    (?:udiff(?:_u?assoc)?)|
    (?:uintersect(?:_u?assoc)?)|
    (?:unique)|
    (?:unshift)|
    (?:values)|
    (?:walk(?:_recursive)?)
    ))?',
    // pcre functions
    'preg_(?:
    filter|
    grep|
    last_error|
    match(?:_all)?|
    quote|
    replace(?:_callback)?|
    split)',
    // magic methods
    '__(?:
    construct|destruct|call|callStatic|get|set|isset|unset|sleep|wakeup|toString|invoke|set_state|clone)',
    
    'str(?:_(?:getcsv|ireplace|pad|repeat|replace|rot13|shuffle|split|word_count))',
    'str(?:casecmp|chr|cmp|coll|cspn|ip_tags|ipcslashes|ipos|ipslashes|istr|len|natcasecmp|natcmp|ncasecmp|ncmp|pbrk|pos|rchr|rev|ripos|rpos|spn|str|tok|tolower|toupper|tr)',
    'substr(_compare|_count|_replace)?'
    
    );
    
  public $types = array('false', 'null', 'true', 'NULL');
  public $oo_separators = array('::', '-&gt;');
  public $ignore_outside_strict = false;
  
  public function __construct()
  {
    
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('php');
    $this->SetInfoVersion('0.3.1');    
    
    // I think the close tag is optional.
    $this->ignore_outside =  array(
      new LuminousBoundaryRule(LUMINOUS_REGEX, 
    "/&lt;\?(php)?/", "/(\?&gt;|$)/")
    );
  
    
    $this->delimited_types = array(
      new LuminousDelimiterRule(0, "DOCCOMMENT", 0, "/**", "*/",
        'luminous_type_callback_doccomment'),
      new LuminousDelimiterRule(0, "DOCCOMMENT", 0, "///", "\n",
        'luminous_type_callback_doccomment'),        
      new LuminousDelimiterRule(0, "COMMENT", 0, "/*", "*/",
        'luminous_type_callback_comment'),
      new LuminousDelimiterRule(0, "COMMENT", LUMINOUS_STOP_AT_END, "//", "\n",
        'luminous_type_callback_comment'),
      new LuminousDelimiterRule(0, "COMMENT", LUMINOUS_STOP_AT_END, "#", "\n",
        'luminous_type_callback_comment'),
      new LuminousDelimiterRule(0, "STRING", 0, "'", "'",
        'luminous_type_callback_php_sstring'),
      new LuminousDelimiterRule(0, "STRING", 0, '"', '"',
      'luminous_type_callback_php_dstring'),
      new LuminousDelimiterRule(0, "STRING", 0, '`', '`',
      'luminous_type_callback_php_dstring'),
      
      new LuminousDelimiterRule(0, "HEREDOC", 
        LUMINOUS_REGEX|LUMINOUS_DYNAMIC_DELIMS|LUMINOUS_COMPLETE, 
        '/(&lt;){3}[\s]*["\']?[\s]*/', null, 
        create_function('&$str', 
        'luminous_type_callback_generic_heredoc($str);
         luminous_type_callback_php_dstring($str);')
         )
    );
    $this->child_grammar = new LuminousGrammarJavaScriptEmbedded();
    
    $this->simple_types[] = new LuminousSimpleRule(3, 'VARIABLE',
      LUMINOUS_REGEX, "/\\$[a-z_][a-z0-9_]*/i");
    
    $this->simple_types[] = luminous_generic_constant();
    $this->SetSimpleTypeRules();
    
    
  }
  
}




class LuminousGrammarVisualBasic extends LuminousGrammar 
{
  
  
  public $operators = array("\+", "\-", "&amp;", "=", "\*", "\^", "\/",  
  "(?<![a-z0-9])and(also?)(?![a-z0-9])", "(?<![a-z0-9])or(else)?(?![a-z0-9])",
  '(?<![a-z0-9])not(?![a-z0-9])', '(?<![a-z0-9])xor(?![a-z0-9])'
  );


  public $types = array(
    "boolean",
    "byte",
    "c(?:bool|byte|char|date|dec|dbl|int|lng|obj|short|sng|str|type)",
    "char",
    "date",
    "decimal",
    "double",
    "enum",
    "false",
    "integer",
    "long",
    "short",
    "string",
    "true");
    
  // HOW MANY?
  public $keywords = array(
    "addhandler", "addressof", "alias", "ansi", "as", "assembly", "auto",
    "byref", "byval", "call", "case", "catch", "const", "declare", "default",
    "delegate", "dim", "directcast", "do", "each", "else(?:if)?", "end", "erase",
    "error", "event", "exit", "finally", "for", "friend", "function", 
    "get(?:type)?", "gosub", "goto", "handles", "if", "implements", "interface",
    "let", "Lib", "like", "loop", "me", "mod", "module", "mustinheret", 
    "mustoverride", "mybase", "myclass", "namespace", "new", "next", "nothing",
    "on", "option", "optional", "overloads", "overridable", "overrides",
    "paramarray", "preserve", "private", "property", "protected", "public", 
    "raiseevent", "readonly", "return", "select", "set", "shadows", "shared",
    "single", "static", "step", "stop", "structure", "sub", "synclock", "then",
    "throw", "to", "try", "typeof", "unicode", "until", "variant", "when", 
    "while", "with", "withevents", "writeonly"
  );
  
  
  
  public $escape_chars = array();
  
  

  public function __construct()
  {
    $this->case_insensitive = true;
    
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('vb');
    $this->SetInfoVersion('0.3.1');        
    
    $this->delimited_types = array(
      new LuminousDelimiterRule(0, "DOCCOMMENT", 0, "'''", "\n"),
      new LuminousDelimiterRule(0, "COMMENT", 0, "'", "\n"),
      new LuminousDelimiterRule(0, "STRING", 0, '"', '"'),
      new LuminousDelimiterRule(0, "PREPROCESSOR", 
        LUMINOUS_REGEX|LUMINOUS_COMPLETE, "/^#.*?(?=($|\"))/m")
    );
    
    $this->SetSimpleTypeRules();
    
    $this->simple_types[] =  new LuminousSimpleRule(3, 'CONSTANT', 
      LUMINOUS_REGEX,
      '/(?<![[:alnum:]_&<])(?-i:\b[A-Z_][A-Z0-9_]{2,})(?![[:alnum:]_])/');
    
  }
  
}


class LuminousGrammarWhitespace extends LuminousGrammar
{
  public function __construct()
  {
    $this->SetInfoAuthor( 
    array('name'=>'Mark Watkinson', 'email'=>'markwatkinson@gmail.com',
    'website'=>'http://www.asgaard.co.uk'));
    $this->SetInfoLanguage('whitespace');
    $this->SetInfoVersion('0.3.1');
    $this->simple_types[] = 
      new LuminousSimpleRule(0, 'COMMENT', LUMINOUS_REGEX, '/[^\s]+/');
    $this->simple_types[] = 
      new LuminousSimpleRule(0, 'WHITESPACE_SPACE', 0, ' ');
    $this->simple_types[] = 
      new LuminousSimpleRule(0, 'WHITESPACE_TAB', 0, "\t");
  }
  
}

/// \endcond
